﻿Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.Globalization
Imports System.Security
Imports System.Security.Permissions

Namespace System.Workflow.Runtime
    Friend NotInheritable Class PerformanceCounterManager
        ' Methods
        Shared Sub New()
            Dim dataArray As PerformanceCounterData() = New PerformanceCounterData(20  - 1) {}
            Dim mappings As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Creation, PerformanceCounterOperation.Increment) }
            dataArray(0) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesCreatedName, ExecutionStringManager.PerformanceCounterSchedulesCreatedDescription, PerformanceCounterType.NumberOfItems64, mappings)
            Dim mappingArray2 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Creation, PerformanceCounterOperation.Increment) }
            dataArray(1) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesCreatedRateName, ExecutionStringManager.PerformanceCounterSchedulesCreatedRateDescription, PerformanceCounterType.RateOfCountsPerSecond64, mappingArray2)
            Dim mappingArray3 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Unloading, PerformanceCounterOperation.Increment) }
            dataArray(2) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesUnloadedName, ExecutionStringManager.PerformanceCounterSchedulesUnloadedDescription, PerformanceCounterType.NumberOfItems64, mappingArray3)
            Dim mappingArray4 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Unloading, PerformanceCounterOperation.Increment) }
            dataArray(3) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesUnloadedRateName, ExecutionStringManager.PerformanceCounterSchedulesUnloadedRateDescription, PerformanceCounterType.RateOfCountsPerSecond64, mappingArray4)
            Dim mappingArray5 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Loading, PerformanceCounterOperation.Increment) }
            dataArray(4) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesLoadedName, ExecutionStringManager.PerformanceCounterSchedulesLoadedDescription, PerformanceCounterType.NumberOfItems64, mappingArray5)
            Dim mappingArray6 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Loading, PerformanceCounterOperation.Increment) }
            dataArray(5) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesLoadedRateName, ExecutionStringManager.PerformanceCounterSchedulesLoadedRateDescription, PerformanceCounterType.RateOfCountsPerSecond64, mappingArray6)
            Dim mappingArray7 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Completion, PerformanceCounterOperation.Increment) }
            dataArray(6) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesCompletedName, ExecutionStringManager.PerformanceCounterSchedulesCompletedDescription, PerformanceCounterType.NumberOfItems64, mappingArray7)
            Dim mappingArray8 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Completion, PerformanceCounterOperation.Increment) }
            dataArray(7) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesCompletedRateName, ExecutionStringManager.PerformanceCounterSchedulesCompletedRateDescription, PerformanceCounterType.RateOfCountsPerSecond64, mappingArray8)
            Dim mappingArray9 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Suspension, PerformanceCounterOperation.Increment), New PerformanceCounterActionMapping(PerformanceCounterAction.Resumption, PerformanceCounterOperation.Decrement) }
            dataArray(8) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesSuspendedName, ExecutionStringManager.PerformanceCounterSchedulesSuspendedDescription, PerformanceCounterType.NumberOfItems64, mappingArray9)
            Dim mappingArray10 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Suspension, PerformanceCounterOperation.Increment) }
            dataArray(9) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesSuspendedRateName, ExecutionStringManager.PerformanceCounterSchedulesSuspendedRateDescription, PerformanceCounterType.RateOfCountsPerSecond64, mappingArray10)
            Dim mappingArray11 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Termination, PerformanceCounterOperation.Increment) }
            dataArray(10) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesTerminatedName, ExecutionStringManager.PerformanceCounterSchedulesTerminatedDescription, PerformanceCounterType.NumberOfItems64, mappingArray11)
            Dim mappingArray12 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Termination, PerformanceCounterOperation.Increment) }
            dataArray(11) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesTerminatedRateName, ExecutionStringManager.PerformanceCounterSchedulesTerminatedRateDescription, PerformanceCounterType.RateOfCountsPerSecond64, mappingArray12)
            Dim mappingArray13 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Creation, PerformanceCounterOperation.Increment), New PerformanceCounterActionMapping(PerformanceCounterAction.Loading, PerformanceCounterOperation.Increment), New PerformanceCounterActionMapping(PerformanceCounterAction.Unloading, PerformanceCounterOperation.Decrement), New PerformanceCounterActionMapping(PerformanceCounterAction.Completion, PerformanceCounterOperation.Decrement), New PerformanceCounterActionMapping(PerformanceCounterAction.Termination, PerformanceCounterOperation.Decrement), New PerformanceCounterActionMapping(PerformanceCounterAction.Aborted, PerformanceCounterOperation.Decrement) }
            dataArray(12) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesInMemoryName, ExecutionStringManager.PerformanceCounterSchedulesInMemoryDescription, PerformanceCounterType.NumberOfItems64, mappingArray13)
            Dim mappingArray14 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Executing, PerformanceCounterOperation.Increment), New PerformanceCounterActionMapping(PerformanceCounterAction.NotExecuting, PerformanceCounterOperation.Decrement) }
            dataArray(13) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesExecutingName, ExecutionStringManager.PerformanceCounterSchedulesExecutingDescription, PerformanceCounterType.NumberOfItems64, mappingArray14)
            Dim mappingArray15 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Idle, PerformanceCounterOperation.Increment) }
            dataArray(14) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesIdleRateName, ExecutionStringManager.PerformanceCounterSchedulesIdleRateDescription, PerformanceCounterType.RateOfCountsPerSecond64, mappingArray15)
            Dim mappingArray16 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Runnable, PerformanceCounterOperation.Increment), New PerformanceCounterActionMapping(PerformanceCounterAction.NotExecuting, PerformanceCounterOperation.Decrement) }
            dataArray(15) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesRunnableName, ExecutionStringManager.PerformanceCounterSchedulesRunnableDescription, PerformanceCounterType.NumberOfItems64, mappingArray16)
            Dim mappingArray17 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Aborted, PerformanceCounterOperation.Increment) }
            dataArray(&H10) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesAbortedName, ExecutionStringManager.PerformanceCounterSchedulesAbortedDescription, PerformanceCounterType.NumberOfItems64, mappingArray17)
            Dim mappingArray18 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Aborted, PerformanceCounterOperation.Increment) }
            dataArray(&H11) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesAbortedRateName, ExecutionStringManager.PerformanceCounterSchedulesAbortedRateDescription, PerformanceCounterType.RateOfCountsPerSecond64, mappingArray18)
            Dim mappingArray19 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Persisted, PerformanceCounterOperation.Increment) }
            dataArray(&H12) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesPersistedName, ExecutionStringManager.PerformanceCounterSchedulesPersistedDescription, PerformanceCounterType.NumberOfItems64, mappingArray19)
            Dim mappingArray20 As PerformanceCounterActionMapping() = New PerformanceCounterActionMapping() { New PerformanceCounterActionMapping(PerformanceCounterAction.Persisted, PerformanceCounterOperation.Increment) }
            dataArray(&H13) = New PerformanceCounterData(ExecutionStringManager.PerformanceCounterSchedulesPersistedRateName, ExecutionStringManager.PerformanceCounterSchedulesPersistedRateDescription, PerformanceCounterType.RateOfCountsPerSecond64, mappingArray20)
            PerformanceCounterManager.s_DefaultPerformanceCounters = dataArray
        End Sub

        Friend Sub New()
        End Sub

        Friend Function CreateCounters(ByVal name As String) As List([Of] PerformanceCounter)
            Dim list As New List([Of] PerformanceCounter) { New PerformanceCounter(PerformanceCounterManager.c_PerformanceCounterCategoryName, name, "_Global_", 0) }
            If Not String.IsNullOrEmpty(Me.m_instanceName) Then
                list.Add(New PerformanceCounter(PerformanceCounterManager.c_PerformanceCounterCategoryName, name, Me.m_instanceName, False))
            End If
            Return list
        End Function

        Friend Sub Initialize(ByVal runtime As WorkflowRuntime)
            AddHandler runtime.WorkflowExecutorInitializing, New EventHandler([Of] WorkflowExecutorInitializingEventArgs)(AddressOf Me.WorkflowExecutorInitializing)
        End Sub

        Private Sub Notify(ByVal action As PerformanceCounterAction, ByVal executor As WorkflowExecutor)
            Dim list As List([Of] PerformanceCounterStatement)
            If Me.m_actionStatements.TryGetValue(action, list) Then
                Dim statement As PerformanceCounterStatement
                For Each statement In list
                    Me.NotifyCounter(action, statement, executor)
                Next
            End If
        End Sub

        Private Sub NotifyCounter(ByVal action As PerformanceCounterAction, ByVal statement As PerformanceCounterStatement, ByVal executor As WorkflowExecutor)
            Dim counter As PerformanceCounter
            For Each counter In statement.Counters
                Select Case statement.Operation
                    Case PerformanceCounterOperation.Increment
                        counter.Increment
                        [Continue]
                    Case PerformanceCounterOperation.Decrement
                        counter.Decrement
                        [Continue]
                End Select
            Next
        End Sub

        Friend Sub SetInstanceName(ByVal instanceName As String)
            Dim dataArray As PerformanceCounterData() = PerformanceCounterManager.s_DefaultPerformanceCounters
            If String.IsNullOrEmpty(instanceName) Then
                Try 
                    New SecurityPermission(PermissionState.Unrestricted).Assert
                    instanceName = Process.GetCurrentProcess.MainModule.ModuleName
                Finally
                    CodeAccessPermission.RevertAssert
                End Try
            End If
            Me.m_instanceName = instanceName
            Dim dictionary As New Dictionary([Of] PerformanceCounterAction, List([Of] PerformanceCounterStatement))
            If PerformanceCounterCategory.Exists(PerformanceCounterManager.c_PerformanceCounterCategoryName) Then
                Dim i As Integer
                For i = 0 To dataArray.Length - 1
                    Dim data As PerformanceCounterData = dataArray(i)
                    Dim j As Integer
                    For j = 0 To data.Mappings.Length - 1
                        Dim mapping As PerformanceCounterActionMapping = data.Mappings(j)
                        If Not dictionary.ContainsKey(mapping.Action) Then
                            dictionary.Add(mapping.Action, New List([Of] PerformanceCounterStatement))
                        End If
                        Dim list As List([Of] PerformanceCounterStatement) = dictionary.Item(mapping.Action)
                        Dim item As New PerformanceCounterStatement(Me.CreateCounters(data.Name), mapping.Operation)
                        list.Add(item)
                    Next j
                Next i
            End If
            Me.m_actionStatements = dictionary
        End Sub

        Friend Sub Uninitialize(ByVal runtime As WorkflowRuntime)
            RemoveHandler runtime.WorkflowExecutorInitializing, New EventHandler([Of] WorkflowExecutorInitializingEventArgs)(AddressOf Me.WorkflowExecutorInitializing)
        End Sub

        Private Sub WorkflowExecutionEvent(ByVal sender As Object, ByVal e As WorkflowExecutionEventArgs)
            Dim creation As PerformanceCounterAction
            If (sender Is Nothing) Then
                Throw New ArgumentNullException("sender")
            End If
            If Not GetType(WorkflowExecutor).IsInstanceOfType(sender) Then
                Throw New ArgumentException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.InvalidArgumentType, New Object() { "sender", GetType(WorkflowExecutor).ToString }))
            End If
            Dim executor As WorkflowExecutor = DirectCast(sender, WorkflowExecutor)
            Select Case e.EventType
                Case WorkflowEventInternal.Created
                    creation = PerformanceCounterAction.Creation
                    Exit Select
                Case WorkflowEventInternal.Completing, WorkflowEventInternal.Idle, WorkflowEventInternal.Suspending, WorkflowEventInternal.Resuming, WorkflowEventInternal.Persisting, WorkflowEventInternal.Unloading, WorkflowEventInternal.Exception, WorkflowEventInternal.Terminating, WorkflowEventInternal.Aborting
                    Return
                Case WorkflowEventInternal.Completed
                    creation = PerformanceCounterAction.Completion
                    Exit Select
                Case WorkflowEventInternal.SchedulerEmpty
                    creation = PerformanceCounterAction.Idle
                    Exit Select
                Case WorkflowEventInternal.Suspended
                    creation = PerformanceCounterAction.Suspension
                    Exit Select
                Case WorkflowEventInternal.Resumed
                    creation = PerformanceCounterAction.Resumption
                    Exit Select
                Case WorkflowEventInternal.Persisted
                    creation = PerformanceCounterAction.Persisted
                    Exit Select
                Case WorkflowEventInternal.Unloaded
                    creation = PerformanceCounterAction.Unloading
                    Exit Select
                Case WorkflowEventInternal.Loaded
                    creation = PerformanceCounterAction.Loading
                    Exit Select
                Case WorkflowEventInternal.Terminated
                    creation = PerformanceCounterAction.Termination
                    Exit Select
                Case WorkflowEventInternal.Aborted
                    creation = PerformanceCounterAction.Aborted
                    Exit Select
                Case WorkflowEventInternal.Runnable
                    creation = PerformanceCounterAction.Runnable
                    Exit Select
                Case WorkflowEventInternal.Executing
                    creation = PerformanceCounterAction.Executing
                    Exit Select
                Case WorkflowEventInternal.NotExecuting
                    creation = PerformanceCounterAction.NotExecuting
                    Exit Select
                Case WorkflowEventInternal.Started
                    creation = PerformanceCounterAction.Starting
                    Exit Select
                Case Else
                    Return
            End Select
            Me.Notify(creation, executor)
        End Sub

        Private Sub WorkflowExecutorInitializing(ByVal sender As Object, ByVal e As WorkflowExecutorInitializingEventArgs)
            If (sender Is Nothing) Then
                Throw New ArgumentNullException("sender")
            End If
            If (e Is Nothing) Then
                Throw New ArgumentNullException("e")
            End If
            If Not GetType(WorkflowExecutor).IsInstanceOfType(sender) Then
                Throw New ArgumentException("sender")
            End If
            Dim executor As WorkflowExecutor = DirectCast(sender, WorkflowExecutor)
            AddHandler executor.WorkflowExecutionEvent, New EventHandler([Of] WorkflowExecutionEventArgs)(AddressOf Me.WorkflowExecutionEvent)
        End Sub


        ' Fields
        Private Shared c_PerformanceCounterCategoryName As String = ExecutionStringManager.PerformanceCounterCategory
        Private m_actionStatements As Dictionary([Of] PerformanceCounterAction, List([Of] PerformanceCounterStatement))
        Private m_instanceName As String
        Private Shared s_DefaultPerformanceCounters As PerformanceCounterData()
    End Class
End Namespace

